package com.communal.util;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.TimeZone;

public class AppCalendarISO {

	private boolean check(StringTokenizer p_stringTokenizer, String p_token){
	    try {
	      if (p_stringTokenizer.nextToken().equals(p_token)) {
	        return true;
	      } else {
	        throw new RuntimeException("Missing [" + p_token + "]");
	      }
	    } catch (NoSuchElementException ex) {
	      return false;
	    }
	}
	
	public Calendar getCalendar(String p_isodate) {
	   StringTokenizer st = new StringTokenizer(p_isodate, "-T:.+Z", true);

	   Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
	   calendar.clear();
	   try {
	     
	     if (st.hasMoreTokens()) {
	       int year = Integer.parseInt(st.nextToken());
	       calendar.set(Calendar.YEAR, year);
	     } else {
	        return calendar;
	     }
	     
	     if (check(st, "-") && (st.hasMoreTokens())) {
	        int month = Integer.parseInt(st.nextToken()) - 1;
	        calendar.set(Calendar.MONTH, month);
	     } else {
	        return calendar;
	     }
	     
	     if (check(st, "-") && (st.hasMoreTokens())) {
	       int day = Integer.parseInt(st.nextToken());
	       calendar.set(Calendar.DAY_OF_MONTH, day);
	     } else {
	       return calendar;
	     }
	   
	     if (check(st, "T") && (st.hasMoreTokens())) {
	       int hour = Integer.parseInt(st.nextToken());
	       calendar.set(Calendar.HOUR_OF_DAY, hour);
	     } else {
	       calendar.set(Calendar.HOUR_OF_DAY, 0);
	       calendar.set(Calendar.MINUTE, 0);
	       calendar.set(Calendar.SECOND, 0);
	       calendar.set(Calendar.MILLISECOND, 0);
	       return calendar;
	     }

	     if (check(st, ":") && (st.hasMoreTokens())) {
	       int minutes = Integer.parseInt(st.nextToken());
	       calendar.set(Calendar.MINUTE, minutes);
	     } else {
	       calendar.set(Calendar.MINUTE, 0);
	       calendar.set(Calendar.SECOND, 0);
	       calendar.set(Calendar.MILLISECOND, 0);
	       return calendar;
	     }

	     if (!st.hasMoreTokens()) {
	       return calendar;
	     }
	     String tok = st.nextToken();
	     if (tok.equals(":")) { 
	       if (st.hasMoreTokens()) {
	         int secondes = Integer.parseInt(st.nextToken());
	         calendar.set(Calendar.SECOND, secondes);
	         if (!st.hasMoreTokens()) {
	           return calendar;
	         }
       
	         tok = st.nextToken();
	         if (tok.equals(".")) {
	            String nt = st.nextToken();
	            while (nt.length() < 3) {
	              nt += "0";
	            }
	            nt = nt.substring(0, 3); 
	            int millisec = Integer.parseInt(nt);
	            calendar.set(Calendar.MILLISECOND, millisec);
	            if (!st.hasMoreTokens()) {
	              return calendar;
	            }
	            tok = st.nextToken();
	         } else {
	            calendar.set(Calendar.MILLISECOND, 0);
	         }
	        } else {
	          throw new RuntimeException("No secondes specified");
	        }
	      } else {
	        calendar.set(Calendar.SECOND, 0);
	        calendar.set(Calendar.MILLISECOND, 0);
	      }
	      
	      if (!tok.equals("Z")) { // UTC
	        if (!(tok.equals("+") || tok.equals("-"))) {
	          throw new RuntimeException("only Z, + or - allowed");
	        }
	        boolean plus = tok.equals("+");
	        if (!st.hasMoreTokens()) {
	          throw new RuntimeException("Missing hour field");
	        }
	        int tzhour = Integer.parseInt(st.nextToken());
	        int tzmin = 0;
	        if (check(st, ":") && (st.hasMoreTokens())) {
	          tzmin = Integer.parseInt(st.nextToken());
	        } else {
	          throw new RuntimeException("Missing minute field");
	        }
	        if (plus) {
	          calendar.add(Calendar.HOUR, -tzhour);
	          calendar.add(Calendar.MINUTE, -tzmin);
	        } else {
	          calendar.add(Calendar.HOUR, tzhour);
	          calendar.add(Calendar.MINUTE, tzmin);
	        }
	      }
	    } catch (NumberFormatException ex) {
	      throw new RuntimeException("[" + ex.getMessage() + "] is not an integer");
	    }
	    return calendar;
	  }
}
